//
//  VIZModuleManager.m
//  VIZModuleManager
//
//  Created by 位立志 on 2018/2/8.
//  Copyright © 2018. All rights reserved.
//

@import UserNotifications;

#import "VIZModuleManager.h"
#import <objc/runtime.h>
#import "VIZApplicationDelegateProxy.h"

//所有组件对应模块Class
static NSMutableArray const * VIZModuleClassArray = nil;

@interface VIZModuleManager ()

/**
 所有组件初始化类
 */
@property (nonatomic, strong) NSMutableArray<id<VIZModuleDelegate>> *modules;



@end

@implementation VIZModuleManager

+ (instancetype)sharedInstance {
    static VIZModuleManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
    });
    return instance;
}

+ (void)addModuleClass:(Class)module {
    NSParameterAssert(module && [module isSubclassOfClass:[VIZModule class]]);

    if (!VIZModuleClassArray) {
        VIZModuleClassArray = [NSMutableArray array];
    }

    if (![VIZModuleClassArray containsObject:module]) {
        [VIZModuleClassArray addObject:module];
    }
}


- (NSMutableArray<id<VIZModuleDelegate>> *)modules {
    if (!_modules) {
        _modules = [NSMutableArray array];
    }
    return _modules;
}

- (void)addModule:(id<VIZModuleDelegate>)module {
    if (![self.modules containsObject:module]) {
        [self.modules addObject:module];
    }
}

//根据优先级对组件进行排序
- (void)generateRegistedModules {
    
    [self.modules removeAllObjects];

    // 进行模块排序
    [VIZModuleClassArray sortUsingDescriptors:@[[[NSSortDescriptor alloc] initWithKey:@"priority" ascending:NO]]];

    for (Class cls in VIZModuleClassArray) {
        VIZModule *module = [cls module];
        NSAssert(module, @"module can't be nil of class %@", NSStringFromClass(cls));

        if (![self.modules containsObject:module]) {
            [self.modules addObject:module];
        }
    }
}



- (NSArray<id<VIZModuleDelegate>> *)allModules {
    return self.modules;
}


- (VIZApplicationDelegateProxy *)proxy {
    if (!_proxy) {
        _proxy = [[VIZApplicationDelegateProxy alloc] init];
    }

    return _proxy;
}

@end


static void VIZSwizzleInstanceMethod(Class cls, SEL originalSelector, Class targetCls, SEL swizzledSelector) {
    Method originalMethod = class_getInstanceMethod(cls, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(targetCls, swizzledSelector);
    BOOL didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

@implementation UIApplication (VIZModule)

+ (void)load {
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        VIZSwizzleInstanceMethod(self, @selector(setDelegate:), self, @selector(VIZ_setDelegate:));
    });
}

//方法交换，替换代理
- (void)VIZ_setDelegate:(id <UIApplicationDelegate>)delegate {
    VIZModuleManager.sharedInstance.proxy.realDelegate = delegate;
    [VIZModuleManager.sharedInstance generateRegistedModules];

    [self VIZ_setDelegate:(id <UIApplicationDelegate>)VIZModuleManager.sharedInstance.proxy];
}

@end
